package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.core.redis.RedisCache;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.framework.config.IotClientConfig;
import com.zzyl.nursing.domain.ProductDetail;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * 设备Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-07-20
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{

    @Resource
    private IotClientConfig iotClientConfig;
    @Resource
    private RedisCache redisCache;
    private static final String CACHE_KEY_PREFIX = "iot:all_product";

    @Resource
    private DeviceMapper deviceMapper;


    @Override
    public void syncProductList(Device device) {
        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        ListProductsRequest request = new ListProductsRequest();
        request.setLimit(50);
        ListProductsResponse response = client.listProducts(request);
        if (response.getHttpStatusCode() != 200){
            throw new BaseException("同步产品列表失败");
        }
        List<ProductSummary> products = response.getProducts();

        redisCache.setCacheObject(CACHE_KEY_PREFIX, JSON.toJSONString(products)
                ,60 * 60 * 24 + (int) (Math.random() * 100), TimeUnit.SECONDS);
    }

    @Override
    public List<ProductVo> allProduct() {
        String cacheValue = redisCache.getCacheObject(CACHE_KEY_PREFIX);
        if (StrUtil.isEmpty(cacheValue)){
            return Collections.emptyList();
        }
        return JSONUtil.toList(cacheValue, ProductVo.class);
    }

    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //保存到本地的数据
        validDevice(deviceDto);

        Device insertEntity = new Device();
        BeanUtil.copyProperties(deviceDto, insertEntity);

        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        body.withNodeId(deviceDto.getNodeId());
        body.withDeviceName(deviceDto.getDeviceName());
        body.withProductId(deviceDto.getProductKey());
        request.withBody(body);
        AddDeviceResponse response = client.addDevice(request);
        if (response.getHttpStatusCode() != 201){
            throw new BaseException("注册设备失败");
        }

        if (ObjectUtil.isNotEmpty(response)){
            insertEntity.setIotId(response.getDeviceId());
            if (ObjectUtil.isNotEmpty(response.getAuthInfo())){
                insertEntity.setSecret(response.getAuthInfo().getSecret());
            }
        }
        save(insertEntity);
    }

    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    @Override
    public DeviceDetailVo selectDeviceById(String iotId) {
        Device localDevice = lambdaQuery().eq(Device::getIotId, iotId).one();
        if (ObjectUtil.isEmpty(localDevice)){
            throw new BaseException("设备不存在");
        }
        DeviceDetailVo deviceDetailVo = new DeviceDetailVo();
        BeanUtil.copyProperties(localDevice, deviceDetailVo);

        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(iotId);
        ShowDeviceResponse response = client.showDevice(request);

        if (ObjectUtil.isNotEmpty(response)){
            deviceDetailVo.setDeviceStatus(response.getStatus());
            deviceDetailVo.setNodeType(response.getNodeType());
            deviceDetailVo.setAuthType(response.getAuthInfo().getAuthType());
            String activeTimeStr = response.getActiveTime();
            if(StringUtils.isNotEmpty(activeTimeStr)){
                LocalDateTime activeTime = LocalDateTimeUtil.parse(activeTimeStr, DatePattern.UTC_MS_PATTERN);
                //日期时区转换
                activeTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                        .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();
                deviceDetailVo.setActiveTime(activeTime);
            }
        }
        return deviceDetailVo;
    }

    @Override

    public AjaxResult queryServiceProperties(String iotId) {
        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.withDeviceId(iotId);
        ShowDeviceShadowResponse response = client.showDeviceShadow(request);
        if (response.getHttpStatusCode() != 200){
            throw new BaseException("查询设备属性失败");
        }
        if(ObjectUtil.isEmpty(response.getShadow())){
            throw new BaseException("设备属性为空");
        }
        JSONObject jsonObject = JSONUtil.parseObj(response.getShadow().get(0).getReported().getProperties());
        String eventTime = response.getShadow().get(0).getReported().getEventTime();
        List<Map<String, Object>> list = new ArrayList<>();

        jsonObject.forEach((key, value) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("functionId", key);
            map.put("value", value);
            map.put("eventTime", eventTime);
            list.add(map);
        });
        return AjaxResult.success(list);
    }

    @Override
    public void edit(DeviceDto deviceDto) {
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceName, deviceDto.getDeviceName());
        if (count(queryWrapper) > 0){
            throw new BaseException("设备已存在");
        }
        Device device = getById(deviceDto.getId());
        BeanUtil.copyProperties(deviceDto, device);
        updateById(device);

        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.withDeviceId(device.getIotId());
        UpdateDevice body = new UpdateDevice();
        body.withDeviceName(deviceDto.getDeviceName());
        request.withBody(body);
        UpdateDeviceResponse response = client.updateDevice(request);
        if (response.getHttpStatusCode() != 200){
            log.info("更新失败：{}", response.getHttpStatusCode());
            throw new RuntimeException("华为云更新设备失败");
        }

    }

    @Override
    @Transactional
    public void deleteByIotId(String iotId) {
        deviceMapper.removeByIotId(iotId);

        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.withDeviceId(iotId);
        client.deleteDevice(request);

    }

    @Override
    public List<ProductDetail> getByProductKey(String productKey) {
        if(ObjectUtil.isEmpty(productKey)){
            return new ArrayList<>();
        }
        IoTDAClient client = iotClientConfig.huaWeiIotInstance();
        ShowProductRequest request = new ShowProductRequest();
        request.withProductId(productKey);
        ShowProductResponse response = client.showProduct(request);

        if (200 != response.getHttpStatusCode()) {
            throw new BaseException("查询产品失败");
        }
        List<ServiceCapability> serviceCapabilities = response.getServiceCapabilities();
        List<ProductDetail> productDetails = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(serviceCapabilities)){
            ProductDetail productDetail = new ProductDetail();
            serviceCapabilities.forEach(serviceCapability -> {
                productDetail.setService_id(serviceCapability.getServiceId());
                productDetail.setService_type(serviceCapability.getServiceType());
                List<ServiceProperty> properties = serviceCapability.getProperties();
                if (CollectionUtil.isNotEmpty(properties)){
                    productDetail.setProperties(properties);
                }
            });
            productDetails.add(productDetail);
        }
        return productDetails;
    }

    @Override
    public List<Long> selectNursingIdsByIotIdWithElder(String iotId) {

        return deviceMapper.selectNursingIdsByIotIdWithElder(iotId);
    }

    @Override
    public List<Long> selectNursingIdsByIotIdWithBed(String iotId) {
        return deviceMapper.selectNursingIdsByIotIdWithBed(iotId);
    }

    private void validDevice(DeviceDto deviceDto) {
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Device::getNodeId, deviceDto.getNodeId());
        if (count(queryWrapper) > 0){
            throw new BaseException("设备id重复");
        }

        queryWrapper.clear();
        queryWrapper.eq(Device::getDeviceName, deviceDto.getDeviceName());
        if (count(queryWrapper) > 0){
            throw new BaseException("设备已存在");
        }

        queryWrapper.clear();
        //1.2 设置筛选条件：binding_location，location_type,physical_location_type,product_key查询有数据代表同一位置绑定了相同产品的设备
        queryWrapper.eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                .eq(Device::getLocationType, deviceDto.getLocationType())
                .eq(Device::getPhysicalLocationType, deviceDto.getPhysicalLocationType())
                .eq(Device::getProductKey, deviceDto.getProductKey());
        //1.3 执行查询，获取查询匹配的个数，个数大于0，说明已存在，抛出异常，提示设同一位置绑定了相同产品的设备
        if (count(queryWrapper) > 0){
            log.error("注册设备失败：同一位置绑定了相同产品的设备");
            throw new RuntimeException("注册设备失败：同一位置绑定了相同产品的设备");
        }
    }
}
